package com.loren.demo31.groovy;

import com.alibaba.fastjson.JSONObject;
import com.loren.demo31.service.BusinessService;
import groovy.lang.Binding;
import groovy.lang.GroovyShell;
import groovy.lang.Script;
import lombok.AllArgsConstructor;
import org.codehaus.groovy.ast.stmt.DoWhileStatement;
import org.codehaus.groovy.ast.stmt.Statement;
import org.codehaus.groovy.ast.stmt.WhileStatement;
import org.codehaus.groovy.control.CompilerConfiguration;
import org.codehaus.groovy.control.customizers.SecureASTCustomizer;
import org.codehaus.groovy.syntax.Types;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Component
@AllArgsConstructor
public class GroovyScriptExecutor {

    private final BusinessService businessService;

    public Object executeScriptText(String scriptText) {
        try {
            Matcher matcher = Pattern.compile("\\bimport\\b").matcher(scriptText);
            if (matcher.find()) {
                throw new RuntimeException("不允许使用第三方或自定义的类");
            }
            Binding binding = new Binding();
            JSONObject input = new JSONObject();
            input.put("name", "loren");
            // input - 入参
            binding.setVariable("input", input);
            // 业务类
            binding.setVariable("businessService", this.businessService);
            GroovyShell groovyShell = new GroovyShell(binding, createCompilerConfiguration());
            String imports = "import com.alibaba.fastjson.JSONObject \nimport com.alibaba.fastjson.JSONArray \n";
            Script script = groovyShell.parse(imports + scriptText);
            return script.run();
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 安全控制等配置，如果需要的话
     */
    public CompilerConfiguration createCompilerConfiguration() {
        SecureASTCustomizer secure = new SecureASTCustomizer();
        secure.setClosuresAllowed(true);

        List<Integer> disallowedTokens = new ArrayList<>();
        disallowedTokens.add(Types.KEYWORD_WHILE);
        disallowedTokens.add(Types.KEYWORD_GOTO);
        secure.setDisallowedTokens(disallowedTokens);
        secure.setIndirectImportCheckEnabled(true);

        List<Class<? extends Statement>> disallowedStatements = new ArrayList<>();
        disallowedStatements.add(WhileStatement.class);
        disallowedStatements.add(DoWhileStatement.class);
        secure.setDisallowedStatements(disallowedStatements);

        CompilerConfiguration config = new CompilerConfiguration();
        config.addCompilationCustomizers(secure);
        return config;
    }
}
